package utp.tepc.jogogeneral;

import java.util.*;

public class General implements IGeneral
{
    public static final String NOME_JOGO = "GENERAL";
    public static final Integer SEQUENCIA = 25;
    public static final Integer FULA = 30;
    public static final Integer QUADRA = 40;
    public static final Integer GENERAL = 50;
    public static final int MAX_LANCES = 3;
    public static final int MAX_RODADAS = 10;

    private List<Dado> dados;
    private Jogo jogoControl;

    public General(Jogo j)
    {
	this.jogoControl = j;
	this.dados = new ArrayList<Dado>();

	for (int i = 0; i < 5; i++)
	    dados.add(new Dado());
    }

    public Jogo getJogo()
    {
	return this.jogoControl;
    }

    @Override
    public List<Dado> getDados()
    {
	return dados;
    }
    
    /**
     * Retorna todas as jogdas possiveis com os dados que estão na mesa
     */
    @Override
    public HashMap<String, Integer> getJogadas() throws Exception
    {
	HashMap<String, Integer> jogadas = new HashMap<String, Integer>();

	if (isSequencia())
	    jogadas.put(this.getNomeJogada(SEQUENCIA), SEQUENCIA);

	if (isFula())
	    jogadas.put(this.getNomeJogada(FULA), FULA);

	if (isQuadra())
	    jogadas.put(this.getNomeJogada(QUADRA), QUADRA);

	if (isGeneral())
	    jogadas.put(this.getNomeJogada(GENERAL), GENERAL);

	jogadas.putAll(this.getJogadasPorNumero());

	return jogadas;
    }
    
    @Override
    public boolean temNovaRodada(int rodada)
    {
	if (rodada <= MAX_RODADAS)
	    return true;

	return false;
    }

    @Override
    public boolean temNovoLancamento(int qtd)
    {
	if (qtd >= MAX_LANCES)
	    return false;

	return true;
    }
    
    @Override
    public boolean podeMarcarPonto(HashMap<String, Integer> jogadasMarcadas, String jogadaNova)
    {
	for (String key : jogadasMarcadas.keySet())
	{
	    if (key.contains(jogadaNova))
		return false;
	}

	return true;
    }

    @Override
    public HashMap<String, Integer> getJogadaParaQueimar(HashMap<String, Integer> jogadasRealizadas)
    {
	HashMap<String, Integer> jogadas = new HashMap<String, Integer>();

	if (!jogadasRealizadas.containsKey(this.getNomeJogada(SEQUENCIA)))
	    jogadas.put(this.getNomeJogada(SEQUENCIA), SEQUENCIA);

	if (!jogadasRealizadas.containsKey(this.getNomeJogada(FULA)))
	    jogadas.put(this.getNomeJogada(FULA), FULA);

	if (!jogadasRealizadas.containsKey(this.getNomeJogada(QUADRA)))
	    jogadas.put(this.getNomeJogada(QUADRA), QUADRA);

	if (!jogadasRealizadas.containsKey(this.getNomeJogada(GENERAL)))
	    jogadas.put(this.getNomeJogada(GENERAL), GENERAL);

	for (Integer i = 1; i <= 6; i++)
	{
	    if (!jogadasRealizadas.containsKey(i.toString()))
		jogadas.put(i.toString(), i);
	}

	return jogadas;
    }
    
    @Override
    public String getJogoNome()
    {
	return NOME_JOGO;
    }

    private boolean isGeneral() throws Exception
    {
	int aux = dados.get(0).getNumeroSorteado();

	for (Dado d : dados)
	    if (d.getNumeroSorteado() != aux)
		return false;

	return true;
    }

    @SuppressWarnings(
    { "rawtypes", "unchecked" })
    private boolean isFula() throws Exception
    {
	Hashtable aux = new Hashtable();
	Hashtable result = new Hashtable();

	for (Dado d : dados)
	{
	    if (aux.containsKey(d.getNumeroSorteado()))
	    {
		Integer value = (Integer) aux.get(d.getNumeroSorteado());
		aux.put(d.getNumeroSorteado(), ++value);
	    }
	    else
	    {
		aux.put(d.getNumeroSorteado(), new Integer(1));
	    }
	}

	if (aux.size() != 2)
	    return false;

	for (Dado d : dados)
	{
	    if (aux.containsKey(d.getNumeroSorteado()))
	    {
		result.put("valor-1", aux.get(d.getNumeroSorteado()));
		aux.remove(d.getNumeroSorteado());
		break;
	    }
	}

	for (Dado d : dados)
	{
	    if (aux.containsKey(d.getNumeroSorteado()))
	    {
		result.put("valor-2", aux.get(d.getNumeroSorteado()));
		break;
	    }
	}

	if (result.size() > 0)
	    if (((Integer) result.get("valor-1") == 2 || (Integer) result.get("valor-1") == 3)
		    && ((Integer) result.get("valor-2") == 2 || (Integer) result.get("valor-2") == 3))
		return true;

	return false;
    }

    @SuppressWarnings(
    { "rawtypes", "unchecked" })
    private boolean isQuadra() throws Exception
    {
	Hashtable aux = new Hashtable();

	for (Dado d : dados)
	{
	    if (aux.containsKey(d.getNumeroSorteado()))
	    {
		Integer value = (Integer) aux.get(d.getNumeroSorteado());
		aux.put(d.getNumeroSorteado(), ++value);
	    }
	    else
	    {
		aux.put(d.getNumeroSorteado(), new Integer(1));
	    }
	}

	for (Dado d : dados)
	{
	    if (aux.containsKey(d.getNumeroSorteado()) && (Integer) aux.get(d.getNumeroSorteado()) == 4)
		return true;
	}

	return false;
    }

    private boolean isSequencia() throws Exception
    {
	int result[] = new int[dados.size()];

	for (int i = 0; i < dados.size(); i++)
	    result[i] = dados.get(i).getNumeroSorteado().intValue();

	Arrays.sort(result);

	for (int i = 0; i < result.length - 1; i++)
	    if (result[i] != result[i + 1] - 1)
		return false;

	return true;
    }    

    private String getNomeJogada(Integer tipos)
    {
	if (tipos == SEQUENCIA)
	    return "Sequencia";

	if (tipos == FULA)
	    return "Fula";

	if (tipos == QUADRA)
	    return "Quadra";

	if (tipos == GENERAL)
	    return "General";

	if (tipos > 0)
	    return Integer.toString(tipos);

	return null;
    }

   
    /**
     * Faz a totalização dos pontos agrupados pelo número do dado sorteado
     * 
     * @return
     * @throws Exception
     */
    private HashMap<String, Integer> getJogadasPorNumero() throws Exception
    {
	HashMap<String, Integer> result = new HashMap<String, Integer>();
	Integer aux;

	for (Dado d : this.dados)
	{
	    if (result.containsKey(d.getNumeroSorteado().toString()))
	    {
		aux = d.getNumeroSorteado();
		aux += result.get(d.getNumeroSorteado().toString());
		result.put(d.getNumeroSorteado().toString(), aux.intValue());
	    }
	    else
	    {
		aux = d.getNumeroSorteado();
		result.put(d.getNumeroSorteado().toString(), aux);
	    }
	}

	return result;
    }
}
